package com.taoz.mianshiwa.controller;

import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jd.platform.hotkey.client.callback.JdHotKeyStore;
import com.taoz.mianshiwa.common.BaseResponse;
import com.taoz.mianshiwa.common.DeleteRequest;
import com.taoz.mianshiwa.common.ErrorCode;
import com.taoz.mianshiwa.common.ResultUtils;
import com.taoz.mianshiwa.constant.HotkeyConstant;
import com.taoz.mianshiwa.constant.UserConstant;
import com.taoz.mianshiwa.exception.BusinessException;
import com.taoz.mianshiwa.exception.ThrowUtils;
import com.taoz.mianshiwa.model.dto.question.QuestionQueryRequest;
import com.taoz.mianshiwa.model.dto.questionBank.QuestionBankAddRequest;
import com.taoz.mianshiwa.model.dto.questionBank.QuestionBankEditRequest;
import com.taoz.mianshiwa.model.dto.questionBank.QuestionBankQueryRequest;
import com.taoz.mianshiwa.model.dto.questionBank.QuestionBankUpdateRequest;
import com.taoz.mianshiwa.model.entity.Question;
import com.taoz.mianshiwa.model.entity.QuestionBank;
import com.taoz.mianshiwa.model.entity.User;
import com.taoz.mianshiwa.model.vo.QuestionBankVO;
import com.taoz.mianshiwa.model.vo.QuestionVO;
import com.taoz.mianshiwa.sentinel.ResourceConstant;
import com.taoz.mianshiwa.service.QuestionBankService;
import com.taoz.mianshiwa.service.QuestionService;
import com.taoz.mianshiwa.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 题库接口
 */
@RestController
@RequestMapping("/questionBank")
@Slf4j
public class QuestionBankController {

    @Resource
    private QuestionBankService questionBankService;
    @Resource
    private QuestionService questionService;

    // region 增删改查

    /**
     * 创建题库
     *
     * @param questionBankAddRequest
     * @return
     */
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    @PostMapping("/add")
    public BaseResponse<Long> addQuestionBank(@RequestBody QuestionBankAddRequest questionBankAddRequest) {
        QuestionBank questionBank = new QuestionBank();
        BeanUtils.copyProperties(questionBankAddRequest, questionBank);
        questionBank.setUserId(StpUtil.getLoginIdAsLong());
        // 写入数据库
        boolean result = questionBankService.save(questionBank);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);

        return ResultUtils.success(questionBank.getId());
    }

    /**
     * 删除题库
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteQuestionBank(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(deleteRequest.getId() == null, ErrorCode.PARAMS_ERROR);

        boolean result = questionBankService.removeById(deleteRequest.getId());
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);

        return ResultUtils.success(true);
    }

    /**
     * 更新题库（仅管理员可用）
     *
     * @param questionBankUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateQuestionBank(@RequestBody QuestionBankUpdateRequest questionBankUpdateRequest) {
        ThrowUtils.throwIf(questionBankUpdateRequest.getId() == null, ErrorCode.PARAMS_ERROR);

        QuestionBank questionBank = new QuestionBank();
        BeanUtils.copyProperties(questionBankUpdateRequest, questionBank);
        // 操作数据库
        boolean result = questionBankService.updateById(questionBank);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);

        return ResultUtils.success(true);
    }

    /**
     * 根据 id 获取题库（封装类）
     *
     * @param questionBankQueryRequest
     * @return
     */
    @GetMapping("/get/vo")
    public BaseResponse<QuestionBankVO> getQuestionBankVOById(QuestionBankQueryRequest questionBankQueryRequest) {
        Long id = questionBankQueryRequest.getId();
        ThrowUtils.throwIf(id == null || id <= 0, ErrorCode.PARAMS_ERROR);

        // hotkey
//        String key = HotkeyConstant.BANK_DETAIL_KEY + id;
//        if (JdHotKeyStore.isHotKey(key)) {
//            Object cache = JdHotKeyStore.get(key);
//            if (cache != null) {
//                return ResultUtils.success((QuestionBankVO) cache);
//            }
//        }

        // 查询数据库
        QuestionBank questionBank = questionBankService.getById(id);
        ThrowUtils.throwIf(questionBank == null, ErrorCode.NOT_FOUND_ERROR);
        QuestionBankVO questionBankVO = questionBankService.getQuestionBankVO(questionBank);
        // 分页查询题库下数据
        QuestionQueryRequest questionQueryRequest = new QuestionQueryRequest();
        questionQueryRequest.setQuestionBankId(id);
        questionQueryRequest.setPageSize(questionBankQueryRequest.getPageSize());
        questionQueryRequest.setCurrent(questionBankQueryRequest.getCurrent());
        Page<Question> questionPage = questionService.listQuestionByPage(questionQueryRequest);
        Page<QuestionVO> questionVOPage = questionService.getQuestionVOPage(questionPage);
        questionBankVO.setQuestionPage(questionVOPage);

//        JdHotKeyStore.smartSet(key, questionBankVO);

        // 获取封装类
        return ResultUtils.success(questionBankVO);
    }

    /**
     * 分页获取题库列表（仅管理员可用）
     *
     * @param questionBankQueryRequest
     * @return
     */
    @PostMapping("/list/page")
    @SaCheckRole(UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<QuestionBank>> listQuestionBankByPage(@RequestBody QuestionBankQueryRequest questionBankQueryRequest) {
        long current = questionBankQueryRequest.getCurrent();
        long size = questionBankQueryRequest.getPageSize();
        // 查询数据库
        Page<QuestionBank> questionBankPage = questionBankService.page(new Page<>(current, size));

        return ResultUtils.success(questionBankPage);
    }

    /**
     * 分页获取题库列表（封装类）
     *
     * @param questionBankQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<QuestionBankVO>> listQuestionBankVOByPage(@RequestBody QuestionBankQueryRequest questionBankQueryRequest,
                                                                       HttpServletRequest request) {
        // sentinel限流降级
        String remoteAddr = request.getRemoteAddr();  // 获取请求方的ip地址
        Entry entry = null;
        try {
            entry = SphU.entry(ResourceConstant.LIST_QUESTION_BANK_VO_BY_PAGE, EntryType.IN, 1, remoteAddr);
            // 没有触发降级
            // 查询数据库
            Page<QuestionBank> questionBankPage = questionBankService.page(new Page<>(1, 200));
            // 没有触发异常
            return ResultUtils.success(questionBankService.getQuestionBankVOPage(questionBankPage, request));
        } catch (Throwable e) {
            // 此时有两种可能，如果触发了限流或者熔断，会抛出BlockException
            if (BlockException.isBlockException(e)) {
                // 说明系统不想处理这个请求了
                return ResultUtils.error(ErrorCode.OPERATION_ERROR, "系统繁忙，请稍后重试");
            }
            // 否则就是后面业务出现了异常
            Tracer.trace(e);
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
        } finally {
            if (entry != null) {
                entry.exit(1, remoteAddr);
            }
        }
    }
}